﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using Bling.Util;
using Bling.DSL;
//using Bling.Properties;
using Bling.Vecs;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Media3D;
using System.ComponentModel;
using linq = Microsoft.Linq.Expressions;
using Bling.Reactive;
namespace Bling.Linq {
}

namespace Bling.WPF.Util {
  using System.ComponentModel;
  using System.Collections.Specialized;
  public delegate void TypedDependencyPropertyChangedEventHandler<OWNER, TYPE>(OWNER owner, TYPE oldValue, TYPE newValue) where OWNER : DependencyObject;
  public interface ListChangeHandler<TYPE> {
    PropertyChangedEventHandler PropertyChangedEventHandler { get; }
    NotifyCollectionChangedEventHandler NotifyCollectionChangedEventHandler { get; }
    void addAll(IList<TYPE> list);
    void removeAll(IList<TYPE> list);
  }
}
namespace Bling.WPF {
  using Bling.Linq;
  using Bling.Core;
  using Bling.WPF.Util;

  public class BindIt {
    //public class 
    private class Handle<A,B,C> : IAssign {
      public readonly Microsoft.Action<A, B> Result;
      private readonly LinqBindEval Txt;
      public Handle(Func<Expr<A>, Expr<B>, Expr<C>> LHS, Func<Expr<A>, Expr<B>, Expr<C>> RHS) {
        var Exprs = new List<linq.Expression>();
        Txt = new LinqBindEval() {
          DelayBindsExpr = Exprs,
        };
        var slots = Txt.Parameters;
        var SlotA = slots.NewParameter<A>();
        var SlotB = slots.NewParameter<B>();
        var LHS0 = LHS(SlotA, SlotB);
        var RHS0 = RHS(SlotA, SlotB);
        if (!LHS0.Solve(this, RHS0)) throw new Exception();
        // now...we can 
        var Block = linq.Expression.Block(typeof(void), Exprs.ToArray());
        Result = Txt.Eval<Microsoft.Action<A, B>>(Block);
      }
      bool IAssign.Accept<T>(Expr<T> LHS, Expr<T> RHS) { return Txt.Accept(LHS, RHS); }
      IAssign IAssign.Copy() { return this; }
    }
    public static Microsoft.Action<A,B> DelayBind<A, B, C>(Func<Expr<A>, Expr<B>, Expr<C>> LHS, Func<Expr<A>,Expr<B>, Expr<C>> RHS) {
      return new Handle<A, B, C>(LHS, RHS).Result;
    }
  }

  public interface IDependencyPropertyExpr : IExpr, IHasContainer {
    DependencyObject Target { get; }
    DependencyProperty ReadProperty { get; }
    DependencyProperty WriteProperty { get; }
  }
  public interface IBaseDependencyPropertyExpr<T> : IDependencyPropertyExpr, ICanAssignNowExpr<T>, IBindableExpr<T> { }

  public abstract partial class DependencyPropertyExpr<T> : Ops.Operation<T>, IBaseDependencyPropertyExpr<T>, ICanChangeExpr<T> {
    public abstract Expr BaseTargetValue { get; }
    public abstract DependencyObject Target { get; }
    public abstract Expr BaseContainer { get; }

    public override Expr<T> Expanded {
      get { return null; }
    }
    public override Expr this[int Idx] {
      get { throw new IndexOutOfRangeException(); }
    }
    public override Bling.Ops.IOperator<T> BaseOp {
      get { throw new NotSupportedException(); }
    }

    /// <summary>
    /// Dependency property used for reading.
    /// </summary>
    public DependencyProperty ReadProperty { get; internal set; }

    public DependencyProperty Property { set { WriteProperty = value; ReadProperty = value; } }

    protected override Expr<T> Derivative1(Dictionary<Expr, Expr> Map) {
      return new Constant<T>(default(T)); // treat as constant
    }

    /// <summary>
    /// Dependency property used for writing.
    /// </summary>
    public DependencyProperty WriteProperty { get; internal set; }

    public abstract EventStream Changed { get; }

    public abstract TDelegate SetNow<TDelegate>(Expr<T> value, params IParameterExpr[] Args);
    public abstract bool SetNow(T value);
    public abstract bool DelayBindWith(Expr<T> value, List<Action> DoBind);
    public abstract bool BindWith(Expr<T> value);
    public abstract bool TwoWayBindWith(Expr<T> value);
    public bool BindWith(Expr value) { return BindWith((Expr<T>)value); }

    protected override int GetHashCode0() {
      return BaseTargetValue.GetHashCode() + ReadProperty.GetHashCode() + WriteProperty.GetHashCode();
    }
    protected override bool Equals0(Expr<T> obj) {
      if (!(obj is DependencyPropertyExpr<T>)) return false;
      var other = (DependencyPropertyExpr<T>)obj;
      return other.BaseTargetValue.Equals(BaseTargetValue) && other.ReadProperty == ReadProperty && other.WriteProperty == WriteProperty;
    }
    protected override string ToString1() {

      return (BaseContainer.GetHashCode() % 100) + "." + ReadProperty.Name; // +"{" + Target.GetValue(ReadProperty) + "}";
    }
    // XXX for debug.
    protected object DepCurrentValue { get { return Target.GetValue(ReadProperty); } }
    public abstract Eval<EVAL>.Info<T> StraightEval<EVAL>(Eval<EVAL> txt) where EVAL : Eval<EVAL>;
  }
  /// <summary>
  /// Non-braded Bl value that is a wrapper around a WPF dependency object/property pair.
  /// </summary>
  /// <typeparam name="T"></typeparam>
  public class DependencyPropertyExpr<S, T> : DependencyPropertyExpr<T>, IHasContainer<S, T>, ICanAssignExpr<T, linq.Expression>, IUseInUI<T> where S : DependencyObject {
    public override Expr BaseContainer { get { return Container; } }
    public Expr<S> Container { get { return TargetValue; } }

    public override Expr<T> Expanded {
      get { return null; }
    }
    public override Expr this[int Idx] {
      get { throw new IndexOutOfRangeException(); }
    }
    public override Bling.Ops.IOperator<T> BaseOp {
      get { throw new NotImplementedException(); }
    }

    public Expr<S> TargetValue { get; internal set; }
    public override Expr BaseTargetValue { get { return TargetValue; } }
    /// <summary>
    /// Target dependency object.
    /// </summary>
    public override DependencyObject Target {
      get {
        TargetValue.IsConstant.Assert();
        return (DependencyObject)(object)TargetValue.CurrentValue;
      }
    }
    internal DependencyPropertyExpr() { }
    protected override Eval<EVAL>.Info<T> Eval<EVAL>(Eval<EVAL> txt) {
      if (txt is DependencyPropertyEval<EVAL>) return ((DependencyPropertyEval<EVAL>)txt).PropertyValue(this);
      else return StraightEval<EVAL>(txt);
    }
    public override Eval<EVAL>.Info<T> StraightEval<EVAL>(Eval<EVAL> txt) {
      if (txt is TranslateEval<EVAL>) {
        return ((TranslateEval<EVAL>)txt).NoTranslation(this);
      } else if (txt is LinqEval<EVAL>) {
        var txt0 = ((LinqEval<EVAL>)txt);
        var targetI = txt0.DoEval(TargetValue);
        var ret = new LinqEval<EVAL>.MyInfo<T>() { Value = DatabindingExtensions.DoGetValue<T,EVAL>(txt0, targetI.Value, ReadProperty) };
        txt0.AtLeast(ret, targetI);
        return ret;
      } else if (txt is IDynamicEval<EVAL>) {
        return ((IDynamicEval<EVAL>)txt).Dynamic<T>(DynamicMode.Dynamic);
      }
      throw new NotSupportedException();

    }

    public override bool BindWith(Expr<T> RHS) {
      return (new LinqBindEval()).Accept(this, RHS);
    }
    public override bool DelayBindWith(Expr<T> RHS, List<Action> DoBind) {
      var eval = new LinqBindEval() { DelayBinds = DoBind, };
      if (!eval.Accept(this, RHS)) {
        DoBind = null; return false;
      }
      (eval.DelayBinds != null).Assert();
      //DoBind = eval.DoBind;
      return true;
    }

    public override bool TwoWayBindWith(Expr<T> RHS) {
      return (new LinqBindEval() { DoTwoWay = true }).Accept(this, RHS);
    }
    public linq.Expression Assign<EVAL>(linq.Expression RHS0, IExpressionEval<EVAL, linq.Expression> txt) where EVAL : Eval<EVAL> {
      if (txt is LinqEval<EVAL>) {
        return DatabindingExtensions.DoSetValue<T, EVAL>((LinqEval<EVAL>) txt, (txt).Extract(txt.DoEval(TargetValue)), WriteProperty, RHS0);
      } else throw new NotSupportedException();
    }
    public override TDelegate SetNow<TDelegate>(Expr<T> RHS, params IParameterExpr[] Args) {
      if (RHS is Constant<T> && typeof(TDelegate) == typeof(Action)) {
        var value = ((Constant<T>)RHS).Value;
        var WriteProperty = this.WriteProperty;
        var Target = this.Target;
        Action a = new Action(() => {
          Target.SetValue(WriteProperty, value);
        });
        object o = a;

        return (TDelegate) o;
      } else return (new DefaultLinqEval()).DoSetNow<T, TDelegate>(this, RHS, Args);
    }
    public override bool SetNow(T RHS) {

      Target.SetValue(WriteProperty, RHS);
      return true;
    }
    public override EventStream Changed {
      get {
        var Descriptor = DependencyPropertyDescriptor.FromProperty(ReadProperty, typeof(S));
        if (Descriptor != null) {
          return new ChangeEventStream(Descriptor, this);
        } else {
          var holder = new PropertyHolder<T>();
          holder.Bind(this);
          // XXX: this might not work...
          return holder.AsExpr.BaseChanged;
        }
      }
    }
    private class ChangeEventStream : EventStream {
      private readonly DependencyPropertyDescriptor Descriptor;
      private readonly Func<S> ValueF;
      private readonly EventStream TargetChanged;
      public ChangeEventStream(DependencyPropertyDescriptor Descriptor, DependencyPropertyExpr<S, T> Outer) {
        this.Descriptor = Descriptor;
        ValueF = Outer.TargetValue.AsFunc;
        if (Descriptor == null) {
          // an anonymous property....
          (Outer.TargetValue.IsConstant).Assert();
          var Value = ValueF();

          TargetChanged = EventStream.Null;
        } else {
          (Descriptor != null).Assert();
          TargetChanged = Outer.TargetValue.BaseChanged;
        }
      }
      public override Action Subscribe(Action a) {
        EventHandler e = null;
        var Value = ValueF();
        var TargetUns = TargetChanged.Subscribe(() => {
          Descriptor.RemoveValueChanged(Value, e);
          a();
          e = null; Value = null;
        });
        e = (x, y) => {
          if (e == null) return;
          Descriptor.RemoveValueChanged(Value, e);  // we only go once.
          if (TargetUns != null) TargetUns();
          a();
          e = null; Value = null;
        };
        Descriptor.AddValueChanged(Value, e);
        return () => {
          if (e == null) return;
          Descriptor.RemoveValueChanged(Value, e);
          if (TargetUns != null) TargetUns();
          e = null; Value = null;
        };
      }
    }
  }

  public interface DependencyPropertyEval<SELF> : IEval<SELF>, ExplicitPropertyEval<SELF> where SELF : Eval<SELF> {
    Eval<SELF>.Info<T> PropertyValue<T>(DependencyPropertyExpr<T> value);
  }

  public abstract class LinqDPEval<EVAL> : LinqEval<EVAL>, DependencyPropertyEval<EVAL> where EVAL : Eval<EVAL> {
    public abstract Info<T> PropertyValue<T>(ExplicitPropertyExpr<T> value);
    public abstract Info<T> PropertyValue<T>(DependencyPropertyExpr<T> value);
    protected struct MyTHolder<T> {
      public Func<T> ComputeT;
      public T GetT { get { return ComputeT(); } }
    }
  }
  internal class LinqTargetEval : LinqDPEval<LinqTargetEval> {
    public readonly List<Action<ExplicitClient,Action>> OnBinds = new List<Action<ExplicitClient,Action>>(); 
    public override Eval<LinqTargetEval>.Info<T> PropertyValue<T>(DependencyPropertyExpr<T> value) {
      OnBinds.Add((e,DoBind) => value.Changed.Subscribe(() => {
        if (!e.IsExpired()) 
          DoBind();

      }));
      /*
      var ct = new ChangeTarget<T>(value);
      OnBinds.Add((e,DoBind) => {
        ct.Listeners.Add(() => {
          if (!e.IsExpired())
            DoBind();
        });
      });*/
      return value.StraightEval(this);
    }
    public override Eval<LinqTargetEval>.Info<T> PropertyValue<T>(ExplicitPropertyExpr<T> value) {
      OnBinds.Add((e, DoBind) => {
        value.Changed.Subscribe(() => {
          if (!e.IsExpired())
            DoBind();
        });
      });
      return value.StraightEval(this);
    }
  }

  public class LinqBindEval : LinqDPEval<LinqBindEval>, IAssign, DependencyPropertyEval<LinqBindEval> {
    public readonly linq.ParameterExpression Args;
    internal bool DoTwoWay = false;
    public LinqBindEval() : base() {
      // no slots, manage the one argument ourselves!
      Args = linq.Expression.Parameter(typeof(object[]), "Arguments");
    }
    private LinqBindEval(LinqBindEval toCopy) : base() {
      Args = toCopy.Args;
      foreach (var b in toCopy.BindKeys) BindKeys.Add(b);

      //foreach (var b in toCopy.Binding.Bindings) Binding.Bindings.Add(b);
      foreach (var k in toCopy.Properties)
        Properties[k.Key] = k.Value;
      toCopy.DoTwoWay = DoTwoWay;
    }
    private readonly Dictionary<Expr, int> Properties = new Dictionary<Expr, int>();
    public struct BindKey {
      public linq.Expression Target;
      public PropertyPath Path; //DependencyProperty Property;
    }
    public readonly List<BindKey> BindKeys = new List<BindKey>();

    //public readonly MultiBinding Binding = new MultiBinding();
    public bool Delay = false;
    //public bool DoDelayBind = false;
    public IAssign Copy() {
      return new LinqBindEval(this);
    }

    public override Info<T> PropertyValue<T>(ExplicitPropertyExpr<T> value) {
      if (!Properties.ContainsKey(value)) {
        int index = BindKeys.Count;

        var holder = new MyTHolder<T>() { ComputeT = value.ComputeT };
        BindKeys.Add(new BindKey() {
          Target = linq.Expression.Constant(holder),
          Path = new PropertyPath("GetT"),
        });
        OnBind.Add((e, DoBind) => {
          value.OnBind(new ExplicitClient() {
            Update = e.UpdateTarget,
            IsExpired = () => e.Status == BindingStatus.Detached,
          });
        });
        Properties[value] = index;
      }
      var access = linq.Expression.ArrayAccess(Args, linq.Expression.Constant(Properties[value]));
      linq.Expression convert = linq.Expression.Convert(access, typeof(T));
      convert = Convert(convert, TransformType(typeof(T)));
      return new MyInfo<T>() { Value = convert };
    }


    public override Info<T> PropertyValue<T>(DependencyPropertyExpr<T> value) {
      // be conservative!
      if (!Properties.ContainsKey(value)) {
        int index = BindKeys.Count;
        var Target = value.BaseTargetValue;
        if (!Target.IsConstant) {
          true.Assert();
        }


        var Path = new PropertyPath(value.ReadProperty);
        var txt = new LinqTargetEval() { Parameters = Parameters };
        var TargetE = txt.DoEval(Target).Value;
        TargetE = txt.PopScope(TargetE);

        BindKeys.Add(new BindKey() {
          Target = TargetE,
          Path = Path,
        });
        if (!Target.IsConstant && txt.OnBinds.Count > 0) {
          var actions = txt.OnBinds.ToArray();
          OnBind.Add((e, DoBind) => {
            var ee = new ExplicitClient() {
              Update = e.UpdateTarget,
              IsExpired = () => e.Status == BindingStatus.Detached,
            };
            foreach (var a in actions) a(ee, DoBind);
          });
        }
        Properties[value] = index;
      }
      var access = linq.Expression.ArrayAccess(Args, linq.Expression.Constant(Properties[value]));
      linq.Expression convert = linq.Expression.Convert(access, typeof(T));
      convert = Convert(convert, TransformType(typeof(T)));
      return new MyInfo<T>() { Value = convert };
    }
    public Info<S> PropertyValue<R, S>(Info<R> container, DependencyProperty P) {
      var container0 = ((MyInfo<R>)container).Value;
      if (container0 is linq.ConstantExpression) {
        DependencyObject container1 = (DependencyObject)((linq.ConstantExpression)container0).Value;
        return this.DoEval(new DependencyPropertyExpr<DependencyObject, S>() { TargetValue = container1, Property = P });
      } else if (Delay) {
        // can't support delay.
        throw new NotSupportedException();
      }
      throw new NotSupportedException();
    }
    private readonly List<Action<BindingExpressionBase, Action>> OnBind = new List<Action<BindingExpressionBase, Action>>();
    public List<Action> DelayBinds;
    public List<linq.Expression> DelayBindsExpr;


    private class FindTwoWay<S> : IAssign {
      public Expr<S> Param { get { return new LinqExpr<S>(Param0); } }
      private readonly linq.ParameterExpression Param0;
      public FindTwoWay() {
        Param0 = linq.Expression.Parameter(typeof(S), "UseRHS");
      }
      public int Index { get; private set; }
      public Func<S, object> ResultF { get; private set; }
      public LinqBindEval Eval { set; private get; }
      public IAssign Copy() { return this; }
      public bool Accept<T>(Expr<T> LHS, Expr<T> RHS) {
        if (LHS is DependencyPropertyExpr<T>) {
          Index = Eval.Properties[LHS];
          var txt = new DefaultLinqEval();
          var expr = txt.DoEval(RHS).Value;
          expr = txt.PopScope(expr);

          var block = linq.Expression.Lambda<System.Func<S, T>>(expr, Param0);
          var G = block.Compile();
          ResultF = (s) => G(s);
          return true;
        }
        return false;
      }
    }

    public bool Accept<T>(Expr<T> LHS, Expr<T> RHS) {
      if (!(LHS is DependencyPropertyExpr<T>)) return false;
      //(typeof(T) == TransformType(typeof(T))).Assert();
      PushScope();
      var RHS0 = DoEval(RHS).Value;
      var body = this.PopScope<T>(RHS0);
      body = Convert(body, typeof(T));
      var RHS1 = linq.Expression.Lambda<System.Func<object[], T>>(body, Args);

      (!Delay).Assert();
      linq.Expression MakeMultiBinding;
      {
        var temp = linq.Expression.Parameter(typeof(MultiBinding), "mbind");
        var s0 = linq.Expression.Assign(temp, linq.Expression.New(typeof(MultiBinding)));
        var s1 = linq.Expression.Assign(linq.Expression.Property(temp, "Mode"), linq.Expression.Constant(BindingMode.OneWay));
        var tempB = linq.Expression.Parameter(typeof(BindConverter<T>), "conv");
        var s2 = linq.Expression.Assign(tempB, linq.Expression.New(typeof(BindConverter<T>)));
        var s3 = linq.Expression.Assign(linq.Expression.Field(tempB, "F"), RHS1);
        var s4 = linq.Expression.Assign(linq.Expression.Property(temp, "Converter"), tempB);

        MakeMultiBinding = linq.Expression.Block(typeof(MultiBinding), new linq.ParameterExpression[] { temp, tempB },
          s0, s1, s2, s3, s4, temp);
      }
      var BindingE = linq.Expression.Parameter(typeof(MultiBinding), "Bindings");
      linq.Expression S1;
      linq.Expression Block;
      {
        var Source = typeof(Binding).GetProperty("Source");
        var Path = typeof(Binding).GetProperty("Path");
        var Add = typeof(System.Collections.ObjectModel.Collection<BindingBase>).GetMethod("Add");

        var assigns = new linq.Expression[BindKeys.Count];
        var bindings = linq.Expression.Property(BindingE, "Bindings");

        for (int i = 0; i < BindKeys.Count; i++) {
          var e = BindKeys[i].Target;

          e = linq.Expression.Convert(e, typeof(object));
          var temp = linq.Expression.Parameter(typeof(Binding), "binding");
          var assign0 = linq.Expression.Assign(temp, linq.Expression.New(typeof(Binding)));
          var assign1 = linq.Expression.
            Assign(linq.Expression.Property(temp, Path), linq.Expression.Constant(BindKeys[i].Path));
          var assign2 = linq.Expression.
            Assign(linq.Expression.Property(temp, Source), e);
          var assign3 = linq.Expression.Call(bindings, Add, temp);

          assigns[i] = linq.Expression.Block(
            new linq.ParameterExpression[] { temp },
            assign0, assign1, assign2, assign3);
        }
        if (assigns.Length == 0) S1 = linq.Expression.Empty();
        else {
          var block = linq.Expression.Block(assigns);
          S1 = block;
        }
        var LHS0 = (DependencyPropertyExpr<T>)LHS;

        {
          linq.Expression S0 = linq.Expression.Assign(BindingE, MakeMultiBinding);
          var txt0 = new DefaultLinqEval() { Parameters = Parameters };
          var LHS1 = txt0.DoEval(LHS0.BaseTargetValue).Value;
          LHS1 = txt0.PopScope(LHS1);
          var Temp = linq.Expression.Parameter(typeof(BindingExpressionBase), "expr");
          var S2 = 
            linq.Expression.Assign(Temp, 
              linq.Expression.Call(typeof(BindingOperations).GetMethod("SetBinding"),
              LHS1, linq.Expression.Constant(LHS0.WriteProperty), BindingE));
          //var SX = new linq.Expression[this.OnBind.Count];
          Block = linq.Expression.Block(new linq.ParameterExpression[] { BindingE, Temp }, S0, S1, S2, Temp);
        }
      }
      if (DelayBindsExpr != null) {
        (this.OnBind.Count == 0).Assert();
        DelayBindsExpr.Add(Block);

      } else {
        var DoBind0 = linq.Expression.Lambda<System.Func<BindingExpressionBase>>(Block).Compile();
        Action DoBind = null;
        var OnBind = this.OnBind.ToArray();
        DoBind = () => {
          (Block != null).Assert();
          var e = DoBind0();
          foreach (var a in OnBind) a(e, DoBind);
        };
        if (this.DelayBinds == null) {
          DoBind();
        } else {
          this.DelayBinds.Add(DoBind);
        }
      }
      return true;
    }
    private linq.Expression<System.Func<object[], T>> Convert<T>(linq.Expression body, IParameterExpr[] Ps) {
      var F1 = linq.Expression.Lambda(body, this.Parameters.Flush());
      var param = linq.Expression.Parameter(typeof(object[]), "params");
      // we don't have to create the array!
      var invokes = new linq.Expression[Ps.Length];
      for (int i = 0; i < Ps.Length; i++) {
        invokes[i] = linq.Expression.ArrayAccess(param, linq.Expression.Constant(i, typeof(int)));
        invokes[i] = linq.Expression.Convert(invokes[i], Ps[i].TypeOfT);
      }
      var F2 = linq.Expression.Lambda<System.Func<object[], T>>(
        linq.Expression.Invoke(F1, invokes), param);
      return F2;
    }
    public static Action<SOURCE> DelayBind<SOURCE, T>(Expr<T> RHS, DependencyProperty Property) where SOURCE : DependencyObject {
      var ret = DelayBind<SOURCE,T>(RHS, Property, new IParameterExpr[] { });
      return (source) => ret(source, new object[0]);
    }

    public static Action<SOURCE, object[]> DelayBind<SOURCE,T>(Expr<T> RHS, DependencyProperty Property, IParameterExpr[] Ps) where SOURCE : DependencyObject {
      var eval = new LinqBindEval() { Delay = true };
      foreach (var p in Ps) eval.Parameters.Add(p);

      var RHS0 = eval.DoEval(RHS).Value;
      RHS0 = eval.PopScope<T>(RHS0);

      // the function that we want to return to do databinding.
      var F0 = linq.Expression.Lambda<System.Func<object[], T>>(RHS0, eval.Args);
      var F2 = eval.Convert<System.Func<object[], T>>(F0, Ps);
      var F3 = F2.Compile();
      var keys = eval.BindKeys;
      var properties = new PropertyPath[keys.Count];
      var targets = new System.Func<object[], DependencyObject>[keys.Count];
      for (int i = 0; i < keys.Count; i++) {
        properties[i] = keys[i].Path; // new PropertyPath(keys[i].Property);
        //eval.PushScope();
        //var e = eval.DoEval(keys[i].Target).Value;
        //e = eval.PopScope(e);
        var e = keys[i].Target;
        targets[i] = eval.Convert<DependencyObject>(e, Ps).Compile();
      }
      return (Source, Qs) => {
        var F4 = F3(Qs);
        var Binding = new MultiBinding();
        // copy the bindings.
        for (int i = 0; i < properties.Length; i++) {
          Binding.Bindings.Add(new Binding() { Source = targets[i](Qs), Path = properties[i] });
        }
        Binding.Mode = BindingMode.OneWay;
        Binding.Converter = new LinqBindEval.BindConverter<T>() { F = args => F4(args), G = null };
        var e = BindingOperations.SetBinding(Source, Property, Binding);
      };
    }


    internal class BindConverter<T> : IMultiValueConverter {
      public Func<object[], T> F;
      public Func<T, object[]> G;
      public object Convert(object[] args, Type type, object whatever, System.Globalization.CultureInfo useless) {
        return F(args);
      }
      public object[] ConvertBack(object result, Type[] argTypes, object whatever, System.Globalization.CultureInfo useless) {
        if (G == null) throw new NotSupportedException();
        return G((T)result);
      }
    }
  }
  public interface IDependencyObjectBl<BRAND>
    where BRAND : Brand<BRAND>, IDependencyObjectBl<BRAND>
    { }
  public interface IDependencyObjectBl<T, BRAND> : IDependencyObjectBl<BRAND> 
    where BRAND : Brand<T, BRAND>, IDependencyObjectBl<T, BRAND>
    where T : DependencyObject { }

  public static partial class DatabindingExtensions {
    public static BRAND Property<CNT, BRAND>(this Brand<CNT> Container, Brand<BRAND> Init)
      where BRAND : Brand<BRAND>
      where CNT : Brand<CNT>, IDependencyObjectBl<CNT> {
      var CntT = Brand<CNT>.TypeOfT;
      var Instance = (IDependencyPropertyFactory)
        typeof(DependencyPropertyFactory<>).MakeGenericType(CntT).GetField("Instance").GetValue(null);
      var ret = Instance.BaseAnon<BRAND>()(Container.Provider);
      ret.Bind = Init; return ret;
    }
    public static BRAND Property<CNT, BRAND>(this CNT Container, Brand<BRAND> Init)
      where BRAND : Brand<BRAND>
      where CNT : DependencyObject {
      (Init != null).Assert();
      var Instance = 
        DependencyPropertyFactory<CNT>.Instance;
      var ret = Instance.Anon<BRAND>()(new Constant<CNT>(Container));
      ret.Bind = Init;
      ret = Init.CopyMetaTo(ret);
      return ret;
    }
    public static BRAND Property<CNT, T, BRAND>(this CNT Container, Brand<T,BRAND> Init, Action<T,T> OnChange)
      where BRAND : Brand<T,BRAND>
      where CNT : DependencyObject 
    {
      var Instance = 
        DependencyPropertyFactory<CNT>.Instance;
      var ret = Instance.Anon<BRAND>((x,y) => OnChange((T)x,(T)y))(new Constant<CNT>(Container));
      ret = Init.CopyMetaTo(ret);
      ret.Bind = Init; return ret;
    }

    public static DependencyPropertyExpr<S, T> Property<S, T>(this Expr<S> Container, DependencyProperty Property) where S : DependencyObject {
      return new DependencyPropertyExpr<S, T>() { Property = Property, TargetValue = Container };
    }
    public static DependencyPropertyExpr<S, T> Property<S, T>(this Expr<S> Container, DependencyProperty Read, DependencyProperty Write) where S : DependencyObject {
      return new DependencyPropertyExpr<S, T>() { ReadProperty = Read, WriteProperty = Write, TargetValue = Container };
    }


    public static BRAND Property0<S, BRAND>(this Expr<S> Container, DependencyProperty Property) where BRAND : Brand<BRAND> {

      throw new NotSupportedException();


      //return new DependencyPropertyExpr<S, T>() { Property = Property, TargetValue = Container };
    }

    private static readonly MethodInfo GetValue = typeof(DependencyObject).GetMethod("GetValue");
    private static readonly MethodInfo SetValue = typeof(DependencyObject).GetMethod("SetValue", new Type[] { typeof(DependencyProperty), typeof(object) });

    internal static linq.Expression DoGetValue<T,EVAL>(LinqEval<EVAL> txt, linq.Expression target, DependencyProperty ReadProperty) where EVAL : Eval<EVAL> {
      linq.Expression e = linq.Expression.Convert(linq.Expression.Call(linq.Expression.Convert(target, typeof(DependencyObject)), GetValue, linq.Expression.Constant(ReadProperty, typeof(DependencyProperty))), ReadProperty.PropertyType);
      e = txt.Convert(e, txt.TransformType(typeof(T)));
      return e;
    }
    internal static linq.Expression DoSetValue<T, EVAL>(LinqEval<EVAL> txt, linq.Expression target, DependencyProperty WriteProperty, linq.Expression RHS) where EVAL : Eval<EVAL> {
      RHS = txt.Convert(RHS, WriteProperty.PropertyType);
      return linq.Expression.Call(linq.Expression.Convert(target, typeof(DependencyObject)), SetValue, linq.Expression.Constant(WriteProperty, typeof(DependencyProperty)), linq.Expression.Convert(RHS, typeof(object)));
    }

    private class CommandX : IAssign {
      public Action<DependencyObject, DependencyProperty> F;
      public bool Accept<S>(Expr<S> LHS, Expr<S> RHS) {
        if (LHS is DependencyPropertyExpr<S>) {
          var LHS0 = (DependencyPropertyExpr<S>)LHS;
          F(LHS0.Target, LHS0.WriteProperty);
          return true;
        } else if (LHS is EventExpr<S>) {
          var actions = new List<Action>();
          var txt = new CommandX() {
            F = (a,b) => actions.Add(() => F(a,b)),
          };
          if (txt.Accept(((EventExpr<S>)LHS).Underlying, RHS)) {
            var actions0 = actions.ToArray();
            ((EventExpr<S>)LHS).When.SubscribeForever(() => {
              foreach (var a in actions0) a();
            });
          }
          return true;
        }
        return false;
      }
      public IAssign Copy() { return this; }
    }
    /// <summary>
    /// Clear the current now assigned value of underlying properties.
    /// </summary>
    /// <remarks>WPF dependency property only.</remarks>
    public static void ClearNow<T,BRAND>(this Brand<T,BRAND> self) where BRAND : Brand<T,BRAND> {
      if (!self.Provider.Solve(new CommandX() { F = (a, b) => a.ClearValue(b) }, 
        Brand<BRAND>.Default.Provider)) throw new NotSupportedException();
    }
    /// <summary>
    /// Clear the current constraint of underlying properties.
    /// </summary>
    /// <remarks>WPF dependency property only.</remarks>
    public static void ClearConstraint<T, BRAND>(this Brand<T, BRAND> self) where BRAND : Brand<T, BRAND> {
      if (!self.Provider.Solve(new CommandX() { F = (a, b) => BindingOperations.ClearBinding(a, b) }, 
        Brand<BRAND>.Default.Provider)) throw new NotSupportedException();
    }
    /// <summary>
    /// Stop animation of the underlying dependency property.
    /// </summary>
    /// <param name="capture">Whether to capture the curent value as locally set.</param>
    /// <remarks>WPF dependency property only.</remarks>
    public static void Stop<T, BRAND>(this Brand<T, BRAND> self, bool capture) where BRAND : Brand<T, BRAND> {
      if (!self.Provider.Solve(new CommandX() {
        F = (a, b) => {
          var v = a.GetValue(b);
          ((IAnimatable)a).BeginAnimation(b, null);
          if (capture) a.SetValue(b, v);
        }
      }, Brand<BRAND>.Default)) throw new NotSupportedException();
    }
    public static Animate<T,BRAND> Animate<T, BRAND>(this Brand<T, BRAND> self) where BRAND : Brand<T, BRAND>, ICanInterpolate<BRAND> {
      return new Animate<T, BRAND>() { Target = self };
    }
    public static void Transition<T, BRAND>(this Brand<T, BRAND> Self, BRAND NewValue, DoubleBl Clock) where BRAND : Brand<T, BRAND>, ICanInterpolate<BRAND> {
      var OldValue = Self.Now;
      Self.Stop(false);
      Self.Bind = Clock.Lerp(OldValue, NewValue);

    }

    /// <summary>
    /// Create a value that is animated when this state is entered or exited.
    /// </summary>
    /// <param name="F">Action with which to configure in/out animation parameters.</param>
    /// <returns></returns>
    public static DoubleBl Animate(this State state, Action<Animate<double,DoubleBl>> F) {
      return state.Animate(F, (a) => { }, (a) => { });
    }
    /// <summary>
    /// Create a value that is animated when this state is entered or exited.
    /// </summary>
    /// <param name="In">Action with which to configure in animation parameters.</param>
    /// <param name="Out">Action with which to configure out animation parameters.</param>
    /// <returns></returns>
    public static DoubleBl Animate(this State state, Action<Animate<double, DoubleBl>> In, Action<Animate<double, DoubleBl>> Out) {
      return state.Animate((a) => { }, In, Out);
    }
    /// <summary>
    /// Create a value that is animated when this state is entered or exited.
    /// </summary>
    /// <param name="F">Action with which to configure in/out animation parameters.</param>
    /// <param name="In">Action with which to configure in animation parameters.</param>
    /// <param name="Out">Action with which to configure out animation parameters.</param>
    /// <returns></returns>
    public static DoubleBl Animate(this State state, Action<Animate<double,DoubleBl>> F, Action<Animate<double, DoubleBl>> In, Action<Animate<double, DoubleBl>> Out) {
      var slider = new SliderBl();
      var a = slider.Value[state.In].Animate();
      F(a); In(a);
      a.To = 1d;

      a = slider.Value[state.Out].Animate();
      F(a); Out(a);
      a.To = 0d;
      return slider.Value;

    }

    /// <summary>
    /// Clear all values, binding, and animation.
    /// </summary>
    /// <param name="capture">Whether to capture the curent value as locally set.</param>
    /// <remarks>WPF dependency property only.</remarks>
    public static void ClearAll<T, BRAND>(this Brand<T, BRAND> self, bool capture) where BRAND : Brand<T, BRAND> {
      if (!self.Provider.Solve(new CommandX() {
        F = (a, b) => {
          var v = a.GetValue(b);
          a.ClearValue(b);
          BindingOperations.ClearBinding(a, b);
          if (a is IAnimatable) ((IAnimatable)a).BeginAnimation(b, null);
          if (capture) a.SetValue(b, v);
        }
      }, new Constant<T>(default(T)))) throw new NotSupportedException();
    }
    public static GetProperty<OWNER, TYPE> NewProperty<OWNER, TYPE>(this string name) where OWNER : DependencyObject {
      var dp = DependencyProperty.Register(name, typeof(TYPE), typeof(OWNER));
      return new GetProperty<OWNER, TYPE>() { Property = dp };
    }
    public static GetProperty<OWNER, TYPE> NewProperty<OWNER, TYPE>(this string name, TYPE defaultValue) where OWNER : DependencyObject {
      var dp = DependencyProperty.Register(name, typeof(TYPE), typeof(OWNER), new PropertyMetadata(defaultValue));
      return new GetProperty<OWNER, TYPE>() { Property = dp };
    }
    public static GetProperty<OWNER, TYPE> NewProperty<OWNER, TYPE>(this string name, TYPE defaultValue, TypedDependencyPropertyChangedEventHandler<OWNER, TYPE> update, Func<OWNER, TYPE, TYPE> coerce) where OWNER : DependencyObject {
      DependencyProperty dp = null;
      dp = DependencyProperty.Register(name, typeof(TYPE), typeof(OWNER), new PropertyMetadata(defaultValue, (x, y) => {
        if (y.Property == dp) update((OWNER)x, (TYPE)y.OldValue, (TYPE)y.NewValue);
      }, (self, value) => coerce((OWNER)self, (TYPE)value)));
      return new GetProperty<OWNER, TYPE>() { Property = dp };
    }
    public static GetProperty<OWNER, TYPE> NewProperty<OWNER, TYPE>(this string name, TYPE defaultValue, TypedDependencyPropertyChangedEventHandler<OWNER, TYPE> update) where OWNER : DependencyObject {
      DependencyProperty dp = null;
      dp = DependencyProperty.Register(name, typeof(TYPE), typeof(OWNER), new PropertyMetadata(defaultValue, (x, y) => {
        if (y.Property == dp) update((OWNER)x, (TYPE)y.OldValue, (TYPE)y.NewValue);
      }));
      return new GetProperty<OWNER, TYPE>() { Property = dp };
    }
    public static GetProperties<OWNER, TYPE> NewProperties<OWNER, TYPE>(this string name, int count) where OWNER : DependencyObject {
      var Properties = new DependencyProperty[count];
      for (int i = 0; i < count; i++) {
        Properties[i] = DependencyProperty.Register(name + "_" + i, typeof(TYPE), typeof(OWNER));
      }
      return new GetProperties<OWNER, TYPE>() {
        Properties = Properties,
      };
    }

    public static Expr<T> Bl<T>(this DependencyObject Target, DependencyProperty Property) {
      return new DependencyPropertyExpr<DependencyObject, T>() {
        TargetValue = Target,
        Property = Property,
      };
    }
  }
  /// <summary>
  /// Auxillary class use to configure and execute animations.
  /// </summary>
  public class Animate<T, BRAND> where BRAND : Brand<T, BRAND>, ICanInterpolate<BRAND> {
    internal BRAND Target;
    Func<AnimationTimeline, AnimationTimeline> F = t => t;
    Func<DoubleBl, DoubleBl> Tween0 = null;
    
    /// <summary>
    /// Specify duration of animation in milliseconds.
    /// </summary>
    /// <param name="millis">The timeline's simple duration in milliseconds: the amount of time this timeline takes to
    ///     complete a single forward iteration</param>
    /// <returns>Itself.</returns>
    public Animate<T, BRAND> Duration(double millis) {
      var G = F;
      F = t => G(t).Duration(millis);
      return this;
    }
    /// <summary>
    /// Specify a callback to be called when the animation is completed.
    /// </summary>
    /// <param name="P">Callback called when the animation is done. Argument will be the animated property.</param>
    /// <returns>Itself.</returns>
    public Animate<T, BRAND> Completed(Action<BRAND> P) {
      var G = F;
      F = t => {
        t = G(t);
        t.Completed += (x, y) => {
          P(Target);
        };
        return t;
      };
      return this;
    }
    /// <summary>
    /// If true, stop and capture the value of this animation once it is completed. 
    /// This means that future local updates can affect the value. By default, stop 
    /// on completed is true for an animation, set to false if this is not desired behavior.
    /// </summary>
    /// <returns>Itself.</returns>
    public Animate<T, BRAND> StopOnCompleted(bool b) {
      var G = F;
      F = t => {
        var ret = G(t);
        ret.FillBehavior = b ? FillBehavior.Stop : FillBehavior.HoldEnd;
        return ret;
      };
      return this;
    }


    /// <summary>
    /// Specify duration of animation as a time span.
    /// </summary>
    /// <param name="millis">The timeline's simple duration: the amount of time this timeline takes to
    ///     complete a single forward iteration</param>
    /// <returns>Itself.</returns>
    public Animate<T, BRAND> Duration(TimeSpan span) {
      var G = F;
      F = t => G(t).Duration(span);
      return this;
    }
    /// <summary>
    /// Specify duration of animation as a time span.
    /// </summary>
    /// <param name="millis">The timeline's duration: the amount of time this timeline takes to
    ///     complete a single forward iteration</param>
    /// <returns>Itself.</returns>
    public Animate<T, BRAND> Duration(Duration duration) {
      var G = F;
      F = t => G(t).Duration(duration);
      return this;
    }
    /// <summary>
    /// Sets the time at which this System.Windows.Media.Animation.Timeline
    /// should begin
    /// </summary>
    /// <param name="millis">The time (in millseconds) at which this System.Windows.Media.Animation.Timeline should begin,
    ///     relative to its parent's System.Windows.Media.Animation.Timeline.BeginTime.
    ///     If this timeline is a root timeline, the time is relative to its interactive
    ///     begin time (the moment at which the timeline was triggered). This value may
    ///     be positive, negative.
    ///     The default value is zero</param>
    public Animate<T, BRAND> Delay(double millis) {
      var G = F;
      F = t => G(t).BeginTime(millis);
      return this;
    }
    /// <summary>
    /// Sets the time at which this System.Windows.Media.Animation.Timeline
    /// should begin
    /// </summary>
    /// <param name="span">The time at which this System.Windows.Media.Animation.Timeline should begin,
    ///     relative to its parent's System.Windows.Media.Animation.Timeline.BeginTime.
    ///     If this timeline is a root timeline, the time is relative to its interactive
    ///     begin time (the moment at which the timeline was triggered). This value may
    ///     be positive, negative.
    ///     The default value is zero</param>
    /// <returns></returns>
    public Animate<T, BRAND> Delay(TimeSpan span) {
      var G = F;
      F = t => G(t).BeginTime(span);
      return this;
    }


    /// <summary>
    /// Specify that animation should run forever.
    /// </summary>
    /// <returns>Itself.</returns>
    public Animate<T, BRAND> Forever() {
      var G = F;
      F = t => G(t).Forever();
      return this;
    }
    /// <summary>
    /// Specify that animation should reverse after completing.
    /// </summary>
    /// <returns>Itself.</returns>
    public Animate<T, BRAND> AutoReverse() {
      var G = F;
      F = t => G(t).AutoReverse();
      return this;
    }
    public Animate<T, BRAND> Tween(Func<DoubleBl, DoubleBl> Tween) {
      (Tween0 == null).Assert();
      Tween0 = Tween;
      return this;
    }
    private Action<Action> Delay0;
    public Animate<T, BRAND> Later(Action<Action> Delay0) { this.Delay0 = Delay0; return this;  }

    /// <summary>
    /// Start destination-based animation to specified value. 
    /// </summary>
    public BRAND To {
      set {
        if (Percents0 != null) throw new NotSupportedException();

        //XXXX
        var assign = new ToAnimateAssign();
        var G = Target.CoreInterpolate;
        var To = G(Target, value, assign.Clock);

        if (!Target.Provider.Solve(new ToAnimateAssign() { F = F, Tween = Tween0, Delay = Delay0 }, To)) throw new NotSupportedException();
      }
    }
    private DoubleBl[] Percents0;
    /// <summary>
    /// Set percentages of key frame animation.
    /// </summary>
    /// <param name="Percents">List of percents.</param>
    /// <returns>Itself.</returns>
    public Animate<T, BRAND> Percents(params DoubleBl[] Percents) {
      Percents0 = Percents;
      return this;
    }

    /// <summary>
    /// Start key frame animation according to percents previously specified.
    /// </summary>
    /// <param name="values">List of key values corresponding to previously specified percents.</param>
    public void Keys(params BRAND[] values) {
      if (Tween0 != null) throw new NotSupportedException();
      if (Percents0.Length != values.Length) throw new ArgumentException();
      //if (DoStopOnCompleted) this.Completed(p => p.Stop(true));
      

      var a = new KeyAnimateAssign() { };
      Func<double>[] percents = new Func<double>[Percents0.Length];
      for (int i = 0; i < Percents0.Length; i++) {
        if (!Target.Provider.Solve(a, values[i])) 
          throw new NotSupportedException("cannot animate");
        percents[i] = Percents0[i].AsFunc;
      }
      if (a.Record.Count == 0) throw new NotSupportedException("nothing to animate");
      if (a.When != null) {
        var recs = a.Record.ToArray();
        a.When.SubscribeForever(() => {
          foreach (var r in recs)
            r.Value.Animate(percents, F);

        });

      } else {

        foreach (var r in a.Record)
          r.Value.Animate(percents, F);
      }
    }
  }
  public abstract class BaseCustomAnimation : AnimationTimeline {}
  public class CustomAnimation<T> : BaseCustomAnimation {
    // redo this.
    private readonly System.Func<double, T> CurrentValue;
    public CustomAnimation(Func<DoubleBl, DoubleBl> Tween, Expr<T> RHS, ParameterExpr<double> Clock) {
      var eval = new DefaultLinqEval();
      var clock0 = linq.Expression.Parameter(typeof(double), "Clock");
      eval.Parameters[Clock] = clock0;
      var RHS0 = eval.DoEval(RHS).Value;
      RHS0 = eval.PopScope(RHS0); 
      // convert, if not T
      RHS0 = eval.Convert(RHS0, typeof(T));
      eval = null;

      var lambda = linq.Expression.Lambda<System.Func<double, T>>(RHS0, new linq.ParameterExpression[] { clock0 });
      if (Tween != null) {
        eval = new DefaultLinqEval();
        var param0 = linq.Expression.Parameter(typeof(double), "Tween");
        var tween = eval.DoEval(Tween(new LinqExpr<double>(param0)).Provider).Value;
        tween = eval.PopScope(tween);
        var body = linq.Expression.Invoke(lambda, tween);
        lambda = linq.Expression.Lambda<System.Func<double, T>>(body, new linq.ParameterExpression[] { param0 });
      }
      CurrentValue = lambda.Compile();
    }
    private CustomAnimation(System.Func<double, T> CurrentValue) {
      this.CurrentValue = CurrentValue;
    }
    public override Type TargetPropertyType {
      get { return typeof(T); }
    }
    protected override Freezable CreateInstanceCore() {
      var frozen = new CustomAnimation<T>(CurrentValue);
      if (!frozen.Duration.HasTimeSpan) frozen.Duration = new Duration(TimeSpan.FromSeconds(1));
      return frozen;
    }
    public override object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock) {
      var fraction = animationClock.CurrentTime.Value.TotalSeconds / Duration.TimeSpan.TotalSeconds;
      return CurrentValue(fraction);
    }
  }
  abstract class AnimateAssign : IReactiveAssign {
    public abstract IAssign Copy();
    public EventStream When = null;

    public virtual bool Accept<T>(Expr<T> LHS, Expr<T> RHS, EventStream When) {
      this.When = When;
      if (LHS.Solve(this, RHS)) return true;
      this.When = null;
      return false;
    }
    public virtual bool Accept<T>(Expr<T> LHS, Expr<T> RHS) {
      if (LHS is EventExpr<T>) {
        if (true) throw new Exception("XXX catch in solve");
        When = ((EventExpr<T>)LHS).When;
        return Accept(((EventExpr<T>)LHS).Underlying, RHS);
      }
      return false;
    }
  }

  class ToAnimateAssign : AnimateAssign {
    public Func<AnimationTimeline, AnimationTimeline> F = t => t;
    public Func<DoubleBl, DoubleBl> Tween = null;
    public Action<Action> Delay;
    public readonly ParameterExpr<double> Clock = new ParameterExpr<double>("Clock");
    public override IAssign Copy() { return new ToAnimateAssign() { F = F, Tween = Tween, Delay = Delay }; }
    public override bool Accept<T>(Expr<T> LHS, Expr<T> RHS) {
      // we found the dependency property. 
      if (LHS is DependencyPropertyExpr<T>) {
        var LHS0 = (DependencyPropertyExpr<T>)LHS;
        
        var ani = new CustomAnimation<T>(Tween, RHS, Clock);
        var ani0 = F(ani);
        if (When == null) {
          if (Delay != null) {
            Delay(() => ((IAnimatable)LHS0.Target).BeginAnimation(LHS0.WriteProperty, ani0));
          } else {
            ((IAnimatable)LHS0.Target).BeginAnimation(LHS0.WriteProperty, ani0);
          }
        } else {
          Action DoSet = null;
          if (false && ani0.FillBehavior == FillBehavior.Stop) {
            var replace = new ReplaceEval();
            replace[Clock] = new Constant<double>(1d);
            var RHS1 = replace.Translate(RHS);
            var AsFunc = RHS1.AsFunc;
            DoSet = () => LHS0.Target.SetValue(LHS0.WriteProperty, AsFunc());
          } else DoSet = null;

          When.SubscribeForever(() => {
            if (DoSet != null) DoSet();
            ((IAnimatable)LHS0.Target).BeginAnimation(LHS0.WriteProperty, ani0);
          });
        }
        return true;
      }
      return base.Accept(LHS, RHS);
    }
  }
  abstract class KeyPair {
    public abstract void Animate(Func<double>[] percents, Func<AnimationTimeline, AnimationTimeline> F);
  }
  class KeyPair<T> : KeyPair {
    public DependencyPropertyExpr<T> Target;
    public readonly List<Func<T>> Values = new List<Func<T>>();
    public override void Animate(Func<double>[] percents, Func<AnimationTimeline, AnimationTimeline> F) {
      AnimationTimeline a;
      if (typeof(T) == typeof(double)) {
        var b = new DoubleAnimationUsingKeyFrames();
        for (int i = 0; i < Values.Count; i++) {
          b.KeyFrames.Add(new LinearDoubleKeyFrame((double)(object)Values[i](), 
            KeyTime.FromPercent(percents[i]())));
        }
        a = b;
      } else if (typeof(T) == typeof(Point)) {
        var b = new PointAnimationUsingKeyFrames();
        for (int i = 0; i < Values.Count; i++) {
          b.KeyFrames.Add(new LinearPointKeyFrame((Point)(object)Values[i](), 
            KeyTime.FromPercent(percents[i]())));
        }
        a = b;
      } else if (typeof(T) == typeof(Color)) {
        var b = new ColorAnimationUsingKeyFrames();
        for (int i = 0; i < Values.Count; i++) {
          b.KeyFrames.Add(new LinearColorKeyFrame((Color)(object)Values[i](), 
            KeyTime.FromPercent(percents[i]())));
        }
        a = b;
      } else if (typeof(T) == typeof(bool)) {
        var b = new BooleanAnimationUsingKeyFrames();
        for (int i = 0; i < Values.Count; i++) {
          b.KeyFrames.Add(new DiscreteBooleanKeyFrame((bool)(object)Values[i](), 
            KeyTime.FromPercent(percents[i]())));
        }
        a = b;
      } else if (typeof(T) == typeof(int)) {
        var b = new Int32AnimationUsingKeyFrames();
        for (int i = 0; i < Values.Count; i++) {
          b.KeyFrames.Add(new DiscreteInt32KeyFrame((int)(object)Values[i](), 
            KeyTime.FromPercent(percents[i]())));
        }
        a = b;
      } else throw new NotImplementedException();
      ((IAnimatable)Target.Target).BeginAnimation(Target.WriteProperty, F(a));
    }
  }
  class KeyAnimateAssign : AnimateAssign {
    public override IAssign Copy() { return this; }
    public readonly Dictionary<Expr, KeyPair> Record = new Dictionary<Expr, KeyPair>();
    public override bool Accept<T>(Expr<T> LHS, Expr<T> RHS) {
      if (LHS is DependencyPropertyExpr<T>) {
        var LHS0 = (DependencyPropertyExpr<T>)LHS;
        if (!Record.ContainsKey(LHS0)) Record[LHS0] = new KeyPair<T>() { Target = LHS0 };
        ((KeyPair<T>)Record[LHS0]).Values.Add(RHS.AsFunc);
        return true;
      }
      return base.Accept(LHS, RHS);
    }
  }
  public abstract class GetProperty {
    public DependencyProperty Property { get; internal set; }
    public abstract Expr BaseBaseGet(Expr Container);
  }

  public abstract class GetProperty<S> : GetProperty where S : DependencyObject {
    public abstract Expr BaseGet(Expr<S> Container);
    public abstract void BaseSet(Expr<S> Container, Expr Value);
    public override Expr BaseBaseGet(Expr Container) {
      return BaseGet((Expr<S>) Container);
    }
  }

  public class GetProperty<S, T> : GetProperty<S> where S : DependencyObject {
    public DependencyPropertyExpr<T> this[Expr<S> Container] {
      get { return Container.Property<S,T>(Property); }
    }
    public override Expr BaseGet(Expr<S> Container) {
      return this[Container];
    }
    public override void BaseSet(Expr<S> Container, Expr Value) {
      this[Container].Bind = (Expr<T>) Value;
    }
  }



  public class GetProperties<S, T> where S : DependencyObject {
    internal DependencyProperty[] Properties;
    public int Count { get { return Properties.Length; } }
    public GetProperty<S, T> this[int idx] {
      get { return new GetProperty<S, T>() { Property = Properties[idx] }; }
    }
    public PropertyValues<S,T> this[Expr<S> Container] {
      get { return new PropertyValues<S, T>() { Container = Container, Properties = Properties }; }
    }
  }
  public class PropertyValues<S, T> where S : DependencyObject {
    internal DependencyProperty[] Properties;
    internal Expr<S> Container;
    public DependencyPropertyExpr<T> this[int idx] {
      get { return Container.Property<S,T>(Properties[idx]); }
      set { this[idx].Bind = value; }
    }
  }

  /// <summary>
  /// A dependency object that will create a list of objects whose count can change dynamically. 
  /// </summary>
  /// <typeparam name="T">Type of object that is contained in list.</typeparam>
  public class DynamicArray<T> : DependencyObject {
    private static readonly GetProperty<DynamicArray<T>, int> CountProperty =
      "Count".NewProperty<DynamicArray<T>, int>(0, (x, oldV, newV) => x.CountChanged(oldV, newV));
    private readonly Func<int, T> AddT;
    private readonly Action<int, T> RemT;
    /// <summary>
    /// Number of objects to create. This is a dependency property. 
    /// </summary>
    public IntBl Count {
      get { return CountProperty[this]; }
      set { Count.Bind = value; }
    }
    /// <summary>
    /// Create a new dynamic array with specified add and remove functions.
    /// </summary>
    /// <param name="AddT">Function to call when object is added.</param>
    /// <param name="RemT">Function to call when object is removed.</param>
    public DynamicArray(Func<int, T> AddT, Action<int, T> RemT) {
      this.AddT = AddT; this.RemT = RemT;
    }
    private readonly List<T> Elements = new List<T>();
    /// <summary>
    /// Clear all objects from list. 
    /// </summary>
    public void Clear() {
      while (Elements.Count > 0) {
        var e = Elements[Elements.Count - 1];
        Elements.RemoveAt(Elements.Count - 1);
        RemT(Elements.Count, e);
      }
      Count = 0;
    }
    /// <summary>
    /// Get element by index.
    /// </summary>
    /// <param name="index">Index of element to access.</param>
    /// <returns>Accessed element.</returns>
    public T this[int index] {
      get { return Elements[index]; }
    }
    private void CountChanged(int oldV, int newV) {
      while (Elements.Count < newV)
        Elements.Add(AddT(Elements.Count));
      while (Elements.Count > newV) {
        var e = Elements[Elements.Count - 1];
        Elements.RemoveAt(Elements.Count - 1);
        RemT(Elements.Count, e);
      }
    }
  }
  public interface IDependencyPropertyFactory {
    Func<Expr, BRAND> BaseAnon<BRAND>() where BRAND : Brand<BRAND>;
  }

  internal abstract class PropertyHolder : Animatable {
    public abstract DependencyProperty BaseHolderProperty { get; }
    public abstract Expr AsExpr { get; }
    public static PropertyHolder Make(Type t) {
      var c = typeof(PropertyHolder<>).MakeGenericType(t).GetConstructor(new Type[0]);
      return (PropertyHolder) c.Invoke(new object[0]);
    }
    public abstract void Bind(Expr e);


    public Action<object, object> ChangeF;

  }

  internal class PropertyHolder<T> : PropertyHolder {
    public static readonly DependencyProperty HolderProperty =
      DependencyProperty.Register("Holder", typeof(T), typeof(PropertyHolder<T>), new PropertyMetadata((x,y) => {
        var self = (PropertyHolder<T>) x;
        if (self.ChangeF != null) self.ChangeF(y.OldValue, y.NewValue);
      }));

    public override DependencyProperty BaseHolderProperty { get { return HolderProperty; } }

    public T Holder {
      get { return (T)GetValue(HolderProperty); }
      set { SetValue(HolderProperty, value); }
    }
    protected override Freezable CreateInstanceCore() {
      var prop = new PropertyHolder<T>();
      prop.SetValue(HolderProperty, this.GetValue(HolderProperty));
      return prop;
    }
    public override Expr AsExpr {
      get {
        return new GetProperty<PropertyHolder<T>, T>() {
          Property = HolderProperty
        }[this];
      }
    }
    public override void Bind(Expr e) {
      new GetProperty<PropertyHolder<T>, T>() {
        Property = HolderProperty
      }[this].Bind = (Expr<T>) e;
    }
  }
  /*
  internal class AnonManager : FrameworkElement {
    private AnonManager() : base() { }
    public static readonly AnonManager Instance = new AnonManager();
    public readonly Dictionary<DependencyProperty, List<Action>> Listeners = new Dictionary<DependencyProperty, List<Action>>();
    public void Changed(DependencyProperty p, object oldValue, object newValue) {
      if (Listeners.ContainsKey(p)) {
        Listeners[p].Flush();
      }
    }
  }*/
  public class DependencyPropertyFactory<CNT> : Gen.Generator<Expr<CNT>>, IDependencyPropertyFactory where CNT : DependencyObject {
    public override string Name { get { return "DepProp"; } }
    private readonly Dictionary<PropertyInfo, PropertyHolder> Properties = new Dictionary<PropertyInfo, PropertyHolder>();

    private int AnonCount = 0;

    public Func<Expr, BRAND> BaseAnon<BRAND>() where BRAND : Brand<BRAND> {
      var f = Anon<BRAND>();
      return e => f((Expr<CNT>)e);
    }
    public Func<Expr<CNT>, BRAND> Anon<BRAND>() where BRAND : Brand<BRAND> {
      var name = "Anon" + AnonCount;
      AnonCount += 1;
      var TypeOfT = Brand<BRAND>.TypeOfT;
      /*
      {
        var c = typeof(BRAND).GetConstructor(new Type[0]);
        c.Invoke(new object[0]);
      }*/
      var holder = PropertyHolder.Make(TypeOfT);
      var expr = holder.AsExpr;
      return cnt => {
        return Brand<BRAND>.ToBrand(expr);
      };
    }
    public Func<Expr<CNT>, BRAND> Anon<BRAND>(Action<object,object> Changed) where BRAND : Brand<BRAND> {
      var name = "Anon" + AnonCount;
      AnonCount += 1;
      var TypeOfT = Brand<BRAND>.TypeOfT;
      var holder = PropertyHolder.Make(TypeOfT);
      holder.ChangeF = Changed;
      var expr = holder.AsExpr;
      return cnt => {
        return Brand<BRAND>.ToBrand(expr);
      };
    }

    public override PropertyCode Property(PropertyInfo Property) {
      PropertyHolder holder;
      if (!Properties.ContainsKey(Property)) {
        var TypeOfT = Brand.TypeOfT(Property.PropertyType);
        var Default0 = typeof(Brand<>).MakeGenericType(Property.PropertyType).GetProperty("Default");
        var Default1 = (Brand)Default0.GetAccessors()[0].Invoke(null, new object[0]);
        var Default2 = Default1.Provider.BaseCurrentValue;
        
        holder = PropertyHolder.Make(TypeOfT);
        Properties[Property] = holder;
      /*


        Property.PropertyType.GetConstructor(new Type[0]).Invoke(new object[0]);
        
        var dp0 = DependencyProperty.Register(Property.Name, T, typeof(AnonManager), new PropertyMetadata(Default2, (x, y) => {
          ((AnonManager)x).Changed(y.Property, y.OldValue, y.NewValue);
        }));
        var GetT = (typeof(GetProperty<,>)).MakeGenericType(typeof(AnonManager), T);


        dp = (GetProperty<AnonManager>)GetT.GetConstructor(new Type[0] { }).Invoke(new object[0] { });
        dp.Property = dp0;
        Properties[Property] = dp;
       */
      } else holder = Properties[Property];
      var ToBrand = Brand.ToBrand(Property.PropertyType);

      var pc = new PropertyCode() {
        Get = (cnt) => //ToBrand(dp.BaseGet(AnonManager.Instance)),
          ToBrand(holder.AsExpr),
        Set = (cnt,value) => //dp.BaseSet(AnonManager.Instance, ((Brand) value).Provider),
          holder.Bind(((Brand) value).Provider),
      };

      return pc;
    }
    public new static Func<Expr<CNT>,T> Generate<T>() {
      return Instance.Generate0<T>();
    }
    private Func<Expr<CNT>, T> Generate0<T>() {
      return base.Generate<T>();
    }

    private DependencyPropertyFactory() { }
    public static readonly DependencyPropertyFactory<CNT> Instance = new DependencyPropertyFactory<CNT>();




  }
  [AttributeUsage(AttributeTargets.Property)]
  public class PropertyMetaData : System.Attribute  {
    public object Default;

  }
  public class WayPoint : BrandTypeReveal<int> {
    private readonly Brand[] Subjects;
    public readonly object[] Values;
    public WayPoint(params Brand[] Subjects) {
      this.Subjects = Subjects;
      Values = new object[Subjects.Length];
      for (int i = 0; i < Values.Length; i++) {
        Values[i] = Subjects[i].Provider.BaseCurrentValue;
      }
    }
    public WayPoint(Brand[] Subjects, object[] Values) {
      this.Subjects = Subjects;
      this.Values = Values;
    }
    private DoubleBl t;
    private int idx;
    public void Restore(DoubleBl t) { // should be from zero to one.
      this.t = t;
      for (idx = 0; idx < Subjects.Length; idx++) Subjects[idx].Reveal(this);
    }
    public int Visit<T, BRAND>(Brand<T, BRAND> value) where BRAND : Brand<T, BRAND> {
      var From = value.Now;
      var To = Brand<T, BRAND>.ToBrand(new DSL.Constant<T>((T)Values[idx]));
      value.ClearNow();
      var From0 = ((ICanInterpolate<BRAND>)From);
      value.Bind = From0.CoreInterpolate(From, To, t);
      return 0;
    }
  }
}